﻿using System;
using GuidGen.Contracts;
using GuidGen.Models;
using GuidGen.ViewModels;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NSubstitute;

namespace GuidGen.UnitTests
{
    [TestClass]
    public class MainViewModelTests
    {
        private static IClipboard GetClipboard()
        {
            return Substitute.For<IClipboard>();
        }

        private static IDateTimeService GetDateTimeService()
        {
            return Substitute.For<IDateTimeService>();
        }

        private static IGuidGenerator GetGuidGenerator()
        {
            return Substitute.For<IGuidGenerator>();
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void ConstructorRejectsNullDateTimeService()
        {
            // ReSharper disable ObjectCreationAsStatement
            new MainViewModel(null, GetClipboard(), GetGuidGenerator());
            // ReSharper restore ObjectCreationAsStatement
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void ConstructorRejectsNullClipbarod()
        {
            // ReSharper disable ObjectCreationAsStatement
            new MainViewModel(GetDateTimeService(), null, GetGuidGenerator());
            // ReSharper restore ObjectCreationAsStatement
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void ConstructorRejectsNullGuidGenerator()
        {
            // ReSharper disable ObjectCreationAsStatement
            new MainViewModel(GetDateTimeService(), GetClipboard(), null);
            // ReSharper restore ObjectCreationAsStatement
        }

        [TestMethod]
        public void DoubleClickWithNoSelectionDoesNotCauseException()
        {
            var vm = new MainViewModel(GetDateTimeService(), GetClipboard(), GetGuidGenerator());
            vm.ItemDoubleClick.Execute(null);
        }

        [TestMethod]
        public void DoubleClickCopiesGuidToClipboard()
        {
            var clipboard = GetClipboard();
            var vm = new MainViewModel(GetDateTimeService(), clipboard, GetGuidGenerator());
            var guid = new GeneratedGuid(Guid.NewGuid(), DateTime.MinValue);
            vm.ItemDoubleClick.Execute(guid);
            clipboard.Received().SetText(guid.Guid.ToString());
        }

        [TestMethod]
        public void GenerateGeneratesANewGuid()
        {
            var generator = GetGuidGenerator();
            var vm = new MainViewModel(GetDateTimeService(), GetClipboard(), generator);
            vm.GenerateGuid.Execute(null);
            generator.Received().GenerateGuid();
        }

        [TestMethod]
        public void GenerateCopiesTheNewlyCreatedGuidToClipboard()
        {
            var guid = Guid.NewGuid();
            var generator = GetGuidGenerator();
            generator.GenerateGuid().Returns(guid);
            var clipboard = GetClipboard();
            var vm = new MainViewModel(GetDateTimeService(), clipboard, generator);
            vm.GenerateGuid.Execute(null);
            generator.Received().GenerateGuid();
            clipboard.Received().SetText(guid.ToString());
        }

        [TestMethod]
        public void GeneratePushesOldGuidToHistoryList()
        {
            var guid = Guid.NewGuid();
            var generator = GetGuidGenerator();
            generator.GenerateGuid().Returns(guid);
            var clipboard = GetClipboard();
            var vm = new MainViewModel(GetDateTimeService(), clipboard, generator);
            vm.GenerateGuid.Execute(null);

            Assert.AreEqual(1, vm.LastGuids.Count);
            Assert.IsNotNull(vm.LastGuids[0]);
            Assert.AreEqual(guid, vm.LastGuids[0].Guid);
        }

        [TestMethod]
        public void GenerateTriggersPropertyChangedWithProperPropertyName()
        {
            var vm = new MainViewModel(GetDateTimeService(), GetClipboard(), GetGuidGenerator());
            var called = false;
            vm.PropertyChanged += (s, e) => called = true;
            vm.GenerateGuid.Execute(null);
            Assert.IsTrue(called);
        }

        [TestMethod]
        public void FreshlyConstructedInstanceHasGeneratedGuid()
        {
            var vm = new MainViewModel(GetDateTimeService(), GetClipboard(), GetGuidGenerator());
            Assert.IsNotNull(vm.CurrentGuid);
        }
    }
}